#include <NTP.h>
#include <DateTime.h>
#include <ASocket.h>
#include <Client.h>
#include <Ethernet.h>
#include <Server.h>
#include <PString.h>
#include <Dhcp.h>
#include <Dns.h>
#include <string.h>
#include <WString.h>

//MAC ID（各シールドに記載）
byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

//ipが通ったか
boolean ipAcquired = false;

//DNSクラス
DnsClass targetDns;

//ip格納用バッファ
byte buffer[6];

//NTPサーバのip
byte ntp_dot_nist_dot_jp[] = {133, 243, 238, 243}; // ntp.nict.jp

//各センサピン
int ledPin =  2;
int CurrentPin = 0;
int IlumPin = 1;
int TempPin = 2;

//base64エンコード後の文字列格納用
char mime[65];

void setup()
{

  Serial.begin(9600);
  //内部電圧設定
  analogReference( INTERNAL);
  pinMode(ledPin, OUTPUT); 
  
  ////////////////////////////////////
  /////ベーシック認証用ID＆PASS///////
  ////////////////////////////////////
  basic_make("id:pass");
    
  Serial.println("getting ip...");
  int result = Dhcp.beginWithDHCP(mac);
  
  if(result == 1)
  {
    ipAcquired = true;
    
    Serial.println("ip acquired...");
    
    Dhcp.getMacAddress(buffer);
    Serial.print("mac address: ");
    printArray(&Serial, ":", buffer, 6, 16);
    
    Dhcp.getLocalIp(buffer);
    Serial.print("ip address: ");
    printArray(&Serial, ".", buffer, 4, 10);
    
    Dhcp.getSubnetMask(buffer);
    Serial.print("subnet mask: ");
    printArray(&Serial, ".", buffer, 4, 10);
    
    Dhcp.getGatewayIp(buffer);
    Serial.print("gateway ip: ");
    printArray(&Serial, ".", buffer, 4, 10);
    
    Dhcp.getDhcpServerIp(buffer);
    Serial.print("dhcp server ip: ");
    printArray(&Serial, ".", buffer, 4, 10);
    
    Dhcp.getDnsServerIp(buffer);
    Serial.print("dns server ip: ");
    printArray(&Serial, ".", buffer, 4, 10);
    
    
    //// Do DNS Lookup
    
    targetDns.init("100uhaco.appspot.com", buffer);  //Buffer contains the IP address of the DNS server
    targetDns.resolve();
   
    int results;
       
    while(!(results=targetDns.finished())) ;  //wait for DNS to resolve the name
    
    if(results != 1)
    {
      Serial.print("DNS Error code: ");
      Serial.print(results,DEC);
      alert();
    }
    
    
    targetDns.getIP(buffer);  //buffer now contains the IP address for google.com
    Serial.print("target IP address: ");
    printArray(&Serial, ".", buffer, 4, 10);
    
    //NTP同期
    NTP ntp(ntp_dot_nist_dot_jp);
    DateTime.sync( (ntp.get_unix_gmt() + (9 * 60 * 60)) );
        if( DateTime.available() ){
          Serial.println("NTP OK");
        }
        else{
          Serial.println("NTP FALSE");
          alert();
        }
  }
   else{
      Serial.println("unable to acquire ip address...");
      alert();
  }
}

void loop()
{
  digitalWrite(ledPin, LOW);
  //ポスト済みナンバー
  static int posted =0;
  static int SAMPLE_COUNT =0;
  static int max_current = 0;
  static int current_tmp = 0;
  static int ilum_sum = 0;
  static int temp_sum =0;
  //補正用sec
  int sec;
   
  getTime();
  sec = (int)DateTime.Second; 
  
  //現在のpnumを生成
  int pnum = ((int)DateTime.Hour) * 6+ (int)DateTime.Minute / 10; 
    if(pnum >= 144){
       pnum = pnum - 144 ;
    }
  //10分おき、かつまだポストしていなかった場合
  if( ((int)DateTime.Minute % 10) == 0 && (pnum != posted)){
    int ilum_Value = 0;
    int temp_Value = 0;
    //平均化
    if(SAMPLE_COUNT != 0){
      ilum_Value = ilum_sum / SAMPLE_COUNT ;
      temp_Value = temp_sum / SAMPLE_COUNT ;
    }
    //HTTP通信 
    
    makeMsg(pnum, max_current, ilum_Value, temp_Value);
    
    
    //posted更新
    posted = pnum;
    
    //初期化
    SAMPLE_COUNT =0;
    max_current = 0;
    current_tmp = 0;
    ilum_sum = 0;
    temp_sum =0;
    //点滅
    digitalWrite(ledPin,HIGH);
    delay(1000);
    digitalWrite(ledPin, LOW);
  }
  //30秒ごとにデータを収集
  else if( ( 0 == sec)|| (sec == 30) ){    
      //電力データ
      current_tmp = analogRead(CurrentPin);
        if(max_current < current_tmp){
          max_current = current_tmp;
        }
      //照度データ
      ilum_sum +=analogRead(IlumPin);
      //温度データ
      temp_sum +=analogRead(TempPin);
      SAMPLE_COUNT++;
      Serial.println("logging");
      Serial.println(max_current);
      Serial.println(ilum_sum);
      Serial.println(temp_sum);
      
      delay(30000);
  }

}

//メッセージ作成処理 
void makeMsg(int post_count, int current, int ilum, int temp)
{
  char msg[200];
  PString mystring(msg, sizeof(msg));
  
  mystring.print("GET http://100uhaco.appspot.com/haco/record/");
  mystring.print("?pnum=");
  mystring.print(post_count);
  mystring.print("&temp=");
  mystring.print(temp);
  mystring.print("&light=");
  mystring.print(ilum);
  mystring.print("&watt=");
  mystring.print(current); 
  mystring.println("  HTTP/1.0 ");
  mystring.print("Authorization: Basic ");
  mystring.println(mime);

  
  post(msg);
}


//GAEにポスト
void post(char msg[])
{
   //
   //HTTP request phase
   //
   Client client(buffer,80);

   Serial.println("HTTP connecting...");
  
  if (client.connect()) {
    Serial.println("connected");
    //client.write(msg);
    client.println(msg);
    client.println();
    delay(100);
    Serial.println("disconnecting.");
    client.stop();
   }
}


void getTime(){
     if( DateTime.available() )
    {
       //なぜか一ヶ月遅れなので暫定的に+1
       Serial.print((int)DateTime.Month + 1);
       Serial.print("/");
       Serial.print((int)DateTime.Day);       
       Serial.print(" ");
       Serial.print(((int)DateTime.Hour));
       Serial.print(":");
       Serial.print((int)DateTime.Minute);
       Serial.print(":");
       Serial.print((int)DateTime.Second);
       Serial.println(" JST"); 
    } 
}

//IPadress群を出力するための処理
void printArray(Print *output, char* delimeter, byte* data, int len, int base)
{
  char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

  for(int i = 0; i < len; i++)
  {
    if(i != 0)
      output->print(delimeter);

    output->print(itoa(data[i], buf, base));
  }

  output->println();
}

//
//ベーシック認証用base64エンコード関数郡 
//(Twitterライブラリから拝借)
//

void basic_make(const char *user_and_passwd)
{
	mimeEncode(user_and_passwd);
}

static char mime_code(const char c)
{
	if (c < 26) return c+'A';
	if (c < 52) return c-26+'a';
	if (c < 62) return c-52+'0';
	if (c == 62) return '+';
	return '/';
}

void mimeEncode(const char *buf)
{
	int i = 0, j = 0, c[3];
	while (j < 64 && buf[i]) {
		c[0] = buf[i++];
		c[1] = buf[i] ? buf[i++] : 0;
		c[2] = buf[i] ? buf[i++] : 0;
		mime[j++] = mime_code(c[0]>>2);
		mime[j++] = mime_code(((c[0]<<4)&0x30) | (c[1]>>4));
		mime[j++] = c[1] ? mime_code(((c[1]<<2)&0x3c) | (c[2]>>6)) : '=';
		mime[j++] = c[2] ? mime_code(c[2]&0x3f) : '=';
	}
	mime[j] = 0;
}

void alert(){
  while(1){
       //アラート
      digitalWrite(ledPin,HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
  }
}


